// ShellExtAssistent.cpp : Implementation of CFilerFrogShellExt

#include "stdafx.h"
#include "FilerFrogShellExt.h"
#include "..\FilesRefactor\FileMachine.h"
#include "..\FilerFrogUtils\FilerFrogUtils.h"
#include "FrogMessageBox.h"
#include <uxtheme.h>
#include <vssym32.h>

#pragma comment(lib, "uxtheme")

#pragma warning(disable:4482)

MenuItemsHolder CFilerFrogShellExt::s_MenuItemsHolder;

// CFilerFrogShellExt
CFilerFrogShellExt::CFilerFrogShellExt():
m_ListFilePath(L""),
m_IsHtml(false),
m_IncludeSubfolders(false),
m_Indent(false),
m_IsVistaOs(false),
m_FrogProgressDialog(NULL, this),
m_IsRightClickOnDesktop(false)
{
	AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);	// add flags to support other controls
	m_IsVistaOs = FilerFrogUtils::IsVistaOs();
}

CFilerFrogShellExt::~CFilerFrogShellExt()
{
	int updateInterval = m_FilerFrogSettings.GetCheckForUpdatesSettings();

	int daysPassed = FilerFrogUtils::GetPassedDaysFromLastSavedDay();

	if (daysPassed < 0)
	{
		FilerFrogUtils::SetTodayAsLastSavedDate();		
	}

	if (updateInterval > 0 && daysPassed >= updateInterval)
	{
		// Opens the update
		TCHAR szPath[MAX_PATH];

		if (GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szPath, MAX_PATH))
		{
			wstring updateExePath = FilerFrogUtils::GetFileDirectoyPath(szPath) + L"\\FilerFrogUpdater.exe";
			ShellExecute(NULL, NULL, updateExePath.c_str(), L"/Silent", NULL, SW_SHOWNORMAL);
		}

		FilerFrogUtils::SetTodayAsLastSavedDate();
	}
}

STDMETHODIMP CFilerFrogShellExt::Initialize(LPCITEMIDLIST pidlFolder,LPDATAOBJECT pDataObj,	HKEY hProgID)
{
	m_IsVistaOs = FilerFrogUtils::IsVistaOs();

	FORMATETC fmt = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};

	STGMEDIUM stg = {TYMED_HGLOBAL};
	HDROP hDrop;

	// Run on background
	if (pidlFolder)
	{
		CComPtr<IShellFolder> pDesktop,	pFolder;

		if (FAILED(::SHGetDesktopFolder(&pDesktop)))
		{
			return E_INVALIDARG;
		}

		if (FAILED(pDesktop->BindToObject(pidlFolder, NULL, IID_IShellFolder, (void**)&pFolder)))
		{
			m_IsRightClickOnDesktop = true;
			return S_OK;
		}
		else
		{
			return E_INVALIDARG;
		}
	}

	// Look for CF_HDROP data in the data object. If there
	// is no such data, return an error back to Explorer.
	if (pDataObj == NULL || FAILED(pDataObj->GetData(&fmt, &stg)))
	{
		return E_INVALIDARG;
	}

	// Get a pointer to the actual data.
	hDrop = (HDROP)GlobalLock(stg.hGlobal);

	// Make sure it worked.
	if (hDrop == NULL)
	{
		return E_INVALIDARG;
	}

	// Sanity check make sure there is at least one filename.
	UINT uNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
	HRESULT hr = S_OK;

	if (uNumFiles == 0)
	{
		GlobalUnlock(stg.hGlobal);
		ReleaseStgMedium(&stg);
		return E_INVALIDARG;
	}

	// Get the name of the first file and store it in our
	// member variable m_szFile.
	TCHAR szFile[MAX_PATH];

	m_FilesList.clear();

	for (UINT i=0; i < uNumFiles; i++)
	{
		if (DragQueryFile(hDrop, i, szFile, MAX_PATH) == 0)
		{
			hr = E_INVALIDARG;
		}
		else
		{
			wstring filePath = szFile;
			m_FilesList.push_back(filePath);
		}
	}

	GlobalUnlock(stg.hGlobal);
	ReleaseStgMedium(&stg);

	return hr;
}

HMENU CFilerFrogShellExt::AddMenuSubItem(HMENU hParentMenu, HMENU subMenu, const wstring& name, UINT cmd, UINT pos, MenuPics iconIndex, bool disabled)
{
	MENUITEMINFO menuItemInfo;
	ZeroMemory(&menuItemInfo,sizeof(MENUITEMINFO));

	menuItemInfo.cbSize = sizeof(MENUITEMINFO);

	if (iconIndex == MenuPics::ICON_NONE || disabled)
	{
		menuItemInfo.fMask = MIIM_STRING | MIIM_ID | MIIM_DATA | MIIM_STATE;
	}
	else
	{
		menuItemInfo.fMask = MIIM_STRING | MIIM_ID | MIIM_DATA | MIIM_BITMAP | MIIM_STATE;

		if (m_IsVistaOs)
		{
			menuItemInfo.hbmpItem = s_MenuItemsHolder.m_Bitmaps[iconIndex];
		}
		else
		{
			menuItemInfo.hbmpItem = HBMMENU_CALLBACK;
		}
	}

	if (subMenu != NULL)
	{
		menuItemInfo.fMask = menuItemInfo.fMask | MIIM_SUBMENU;
		menuItemInfo.hSubMenu = subMenu;
	}

	if (disabled)
	{
		menuItemInfo.fState = MFS_DISABLED;
	}
	else
	{
		menuItemInfo.fState = MFS_ENABLED;		
	}

	menuItemInfo.wID = cmd;

	if (!m_IsVistaOs)
	{
		menuItemInfo.dwItemData = (ULONG_PTR)s_MenuItemsHolder.m_Icons[iconIndex];
	}

	TCHAR buffer[256];
	wcscpy_s(buffer, 256, name.c_str());
	menuItemInfo.dwTypeData = buffer;
	menuItemInfo.cch = (UINT)wcslen(menuItemInfo.dwTypeData);

	InsertMenuItem(hParentMenu, pos, TRUE, &menuItemInfo);

	if (subMenu != NULL)
	{
		return subMenu;
	}
	else
	{
		return GetSubMenu(hParentMenu, pos);
	}
}

enum eFileType
{
	Directory,
	Picture,
	JpegPicture,
	EncryptedFile,
	OtherFile,
};

void CFilerFrogShellExt::GetDisabledActionsList(list<FileOps>& disabledOpsList)
{
	disabledOpsList.clear();

	bool isAllPictures = true;
	bool isSomePictures = false;

	bool isAllJpegPictures = true;
	bool isSomeJpegPictures = false;

	bool isAllEncrypted = true;
	bool isSomeEncrypted = true;

	bool isDirectory = true;

	bool isFileCountOne = m_FilesList.size() == 1;

	wstring desktopPath = FilerFrogUtils::GetDesktopDirectory();
	wstring desktopPathAll = FilerFrogUtils::GetDesktopAllDirectory();

	if (m_FilesList.size() > 0)
	{
		wstring currentPath = FilerFrogUtils::GetFileDirectoyPath(*m_FilesList.begin());

		if (desktopPath != currentPath && desktopPathAll != currentPath)
		{
			disabledOpsList.push_back(FileOps::SortDesktop);
			disabledOpsList.push_back(FileOps::SortDesktopRedo);
			disabledOpsList.push_back(FileOps::SortDesktopBlueSky);
			disabledOpsList.push_back(FileOps::SortDesktopDark);
			disabledOpsList.push_back(FileOps::SortDesktopEggPlant);
			disabledOpsList.push_back(FileOps::SortDesktopSunset);
		}
	}	
	
	if (m_FilesList.size()  > 0)
	{
		wstring currentPath = FilerFrogUtils::GetFileDirectoyPath(*m_FilesList.begin());

		if (FilerFrogUtils::IsDirectoryInRoot(currentPath))
		{
			disabledOpsList.push_back(FileOps::MoveUp);
		}
	}

	for (list<wstring>::iterator iter = m_FilesList.begin(); iter != m_FilesList.end(); iter++)
	{
		wstring fileName = *iter;
		FileMachine fileMachine(NULL, fileName);

		if (!FilerFrogUtils::IsDirectory(fileName))
		{
			isDirectory = false;

			wstring ext = L"";
			fileMachine.Extension(ext);

			eFileType fileType = eFileType::OtherFile;

			if (ext == L"jpg" || ext == L"jpeg")
			{
				fileType = eFileType::JpegPicture;	

				isSomePictures = true;
				isSomeJpegPictures = true;

				isAllEncrypted = false;
			}
			else if (ext == L"tif" || ext == L"bmp" || ext == L"tiff" || ext == L"png" || ext == L"gif")
			{
				fileType = eFileType::Picture;	

				isSomePictures = true;

				isAllJpegPictures = false;
				isAllEncrypted = false;
			}
			else if (ext == ENCRYPTION_EXTENSION)
			{
				fileType = eFileType::EncryptedFile;

				isSomeEncrypted = true;

				isAllJpegPictures = false;
				isAllPictures = false;
			}
			else
			{
				isAllJpegPictures = false;
				isAllPictures = false;
				isAllEncrypted = false;
			}
		}
		else
		{
			isAllJpegPictures = false;
			isAllPictures = false;
		}
	}

	if (!isDirectory)
	{
		disabledOpsList.push_back(FileOps::ExtractFilesFromFolder);
	}

	if (!isAllJpegPictures)
	{
		disabledOpsList.push_back(FileOps::PdfImageAlbum);
	}

	if (!isAllPictures)
	{
		disabledOpsList.push_back(FileOps::ShrinkImageFiles);
		disabledOpsList.push_back(FileOps::ShrinkImageFiles25);
		disabledOpsList.push_back(FileOps::ShrinkImageFiles50);
		disabledOpsList.push_back(FileOps::ShrinkImageFiles75);
		disabledOpsList.push_back(FileOps::ShrinkImageFiles25Jpg);
		disabledOpsList.push_back(FileOps::ShrinkImageFiles50Jpg);
		disabledOpsList.push_back(FileOps::ShrinkImageFiles75Jpg);
		disabledOpsList.push_back(FileOps::ShrinkImageFiles100Jpg);
		disabledOpsList.push_back(FileOps::AddLogoToImage);
	}

	if (!isAllEncrypted)
	{
		disabledOpsList.push_back(FileOps::DecryptFiles);
	}

	if (isFileCountOne)
	{
		disabledOpsList.push_back(FileOps::RenameMakeSameName);
	}
}

bool CFilerFrogShellExt::IsInDisabledActionsList(FileOps item, list<FileOps>& disabledOpsList)
{
	for (list<FileOps>::iterator iter = disabledOpsList.begin(); iter !=  disabledOpsList.end(); iter++)
	{
		FileOps value = *iter;

		if (value == item)
		{
			return true;
		}		
	}	

	return false;
}

HMENU CFilerFrogShellExt::AddOperationMenu(const HMENU parentMenu,  UINT& idCmd, const UINT uidFirstCmd, UINT& pos, const FileOps operation, bool disabled, bool shortDescription)
{
	m_MenuCommandMap[idCmd - uidFirstCmd] = operation;

	wstring cmdText =  s_MenuItemsHolder.m_CmdText[operation];

	if (shortDescription)
	{
		string::size_type loc = cmdText.find(L" - ", 0);

		if (loc != wstring::npos)
		{
			cmdText = cmdText.substr(loc + 3); 
		}
	}

	return AddMenuSubItem(parentMenu, NULL, cmdText, idCmd++, pos++, s_MenuItemsHolder.m_CmdIcon[operation], disabled); 
}

void CFilerFrogShellExt::AddSortDesktopMenu(HMENU& mainMenu, UINT& idCmd, UINT& pos, UINT& uidFirstCmd)
{
	// Desktop Sort - Menu Category
	HMENU desktopMenu = CreateMenu();
	AddMenuSubItem(mainMenu, desktopMenu, L"Sort Desktop", idCmd, pos++, MenuPics::ICON_SORT_DESKTOP); 

	// Adds List Of Files sub menus
	{
		UINT pos = 0;

		// Add sort desktop
		AddOperationMenu(desktopMenu, idCmd, uidFirstCmd, pos, FileOps::SortDesktop, false, true);

		InsertMenu(desktopMenu, pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

		DesktopSortConfig desktopSortConfig;
		bool recentDesktopSortFound = desktopSortConfig.LoadFromRegistry();

		AddOperationMenu(desktopMenu, idCmd, uidFirstCmd, pos, FileOps::SortDesktopRedo, !recentDesktopSortFound, true);

		InsertMenu(desktopMenu, pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

		// Add sort desktop
		AddOperationMenu(desktopMenu, idCmd, uidFirstCmd, pos, FileOps::SortDesktopBlueSky, false, true);

		// Add sort desktop
		AddOperationMenu(desktopMenu, idCmd, uidFirstCmd, pos, FileOps::SortDesktopEggPlant, false, true);

		// Add sort desktop
		AddOperationMenu(desktopMenu, idCmd, uidFirstCmd, pos, FileOps::SortDesktopSunset, false, true);

		// Add sort desktop
		AddOperationMenu(desktopMenu, idCmd, uidFirstCmd, pos, FileOps::SortDesktopDark, false, true);
	}
}

HRESULT CFilerFrogShellExt::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags)
{	
	// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
	if (uFlags & CMF_DEFAULTONLY)
	{
		return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
	}

	m_ExplorerController.SetSitePtr(m_spUnkSite);

	list<wstring> tempFilesList;

	if (m_ExplorerController.GetSelectedItemsPath(tempFilesList))
	{
		m_FilesList = tempFilesList;
	}

	if (m_IsVistaOs)
	{
		HTHEME hTheme = OpenThemeData(NULL, VSCLASS_MENU);
		m_IsVistaOs = hTheme != NULL;

		if (hTheme)
		{
			CloseThemeData(hTheme);
			hTheme = NULL;
		}
	}

	m_MenuCommandMap.clear();

	list<FileOps> disabledOpsList;

	UINT idCmd = uidFirstCmd + 1;
	UINT pos = uMenuIndex;

	MENUITEMINFO menuItemInfo;
	ZeroMemory(&menuItemInfo,sizeof(MENUITEMINFO));

	menuItemInfo.cbSize = sizeof(MENUITEMINFO);
	menuItemInfo.fMask = MIIM_STRING | MIIM_SUBMENU | MIIM_ID | MIIM_DATA | MIIM_BITMAP;
	menuItemInfo.wID = uidFirstCmd;

	// Creates Main menu
	HMENU mainMenu = CreateMenu();

	if (m_IsRightClickOnDesktop)
	{
		AddSortDesktopMenu(mainMenu, idCmd, pos, uidFirstCmd);
	}
	else
	{
		GetDisabledActionsList(disabledOpsList);

		bool useDefaultFavoritesMenu = m_FilerFrogSettings.GetFavoritesSettings();

		HMENU favParent = mainMenu;

		if (useDefaultFavoritesMenu)
		{
			// Favorties - Menu Category
			HMENU favMenu = CreateMenu();
			AddMenuSubItem(mainMenu, favMenu, L"Favorites", idCmd, pos++, MenuPics::ICON_HEART);
			favParent = favMenu;
		}

		// Adds Favorites sub menus
		{
			UINT favPos = 0;

			if (!useDefaultFavoritesMenu)
			{
				favPos = pos;
			}

			m_MenuCommandMap[idCmd - uidFirstCmd] = FileOps::ManageFavorites;
			AddMenuSubItem(favParent, NULL, s_MenuItemsHolder.m_CmdText[FileOps::ManageFavorites], idCmd++,  favPos++, s_MenuItemsHolder.m_CmdIcon[FileOps::ManageFavorites]); 

			list<FileOps> favlist;

			CFrogFavoriteDialog::GetFavoritesList(favlist);

			if (favlist.begin() != favlist.end())
			{
				InsertMenu(favParent, favPos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
			}

			list<FileOps>::iterator it;

			for (it = favlist.begin(); it != favlist.end();  ++it)
			{
				int i = *it;
				FileOps op = (FileOps)i;

				if (op == FileOps::MenuSeparator)
				{
					InsertMenu(favParent, favPos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
				}
				else
				{
					AddOperationMenu(favParent, idCmd, uidFirstCmd, favPos, op, IsInDisabledActionsList(op, disabledOpsList));
				}
			}

			if (!useDefaultFavoritesMenu)
			{
				pos = favPos;
			}
		}

		if (useDefaultFavoritesMenu)
		{
			// Organize - Menu Category
			HMENU filesMenu = CreateMenu();
			AddMenuSubItem(mainMenu, filesMenu, L"Organize", idCmd, pos++, MenuPics::ICON_ORGANIZE); 

			// Organize Files Handling sub menus
			{
				UINT pos = 0;	

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::ExtractFilesToFolder);
				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::ExtractFilesFromFolder, IsInDisabledActionsList(FileOps::ExtractFilesFromFolder, disabledOpsList));

				InsertMenu(filesMenu, pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::CopyFiles);

				// Recent Copy Files - Menu Category
				HMENU recentCopyMenu = CreateMenu();
				AddMenuSubItem(filesMenu, recentCopyMenu, L"Copy to (Recent)", idCmd, pos++, MenuPics::ICON_COPY, m_RecentActionsManager.m_CopyCount == 0); 

				for (int i=0; i< m_RecentActionsManager.m_CopyCount; i++)
				{
					m_MenuCommandMap[idCmd - uidFirstCmd] = (FileOps)(FileOps::CopyFilesRecent00 + i);		
					wstring recentName = m_RecentActionsManager.m_LastCopyPaths[i];
					AddMenuSubItem(recentCopyMenu, NULL, recentName, idCmd++, pos++, s_MenuItemsHolder.m_CmdIcon[FileOps::CopyFiles]); 
				}

				InsertMenu(filesMenu, pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::MoveFiles);								

				// Recent Move Files - Menu Category
				HMENU recentMoveMenu = CreateMenu();		
				AddMenuSubItem(filesMenu, recentMoveMenu, L"Move to (Recent)", idCmd, pos++, MenuPics::ICON_MOVE, m_RecentActionsManager.m_MoveCount == 0); 

				for (int i=0; i< m_RecentActionsManager.m_MoveCount; i++)
				{
					m_MenuCommandMap[idCmd - uidFirstCmd] =  (FileOps)(FileOps::MoveFilesRecent00 + i);	
					wstring recentName = m_RecentActionsManager.m_LastMovePaths[i];
					AddMenuSubItem(recentMoveMenu, NULL, recentName, idCmd++, pos++, s_MenuItemsHolder.m_CmdIcon[FileOps::MoveFiles]); 
				}

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::MoveUp, IsInDisabledActionsList(FileOps::MoveUp, disabledOpsList));

				InsertMenu(filesMenu, pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::DeleteZeroLengthFiles);

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::InvertSelection);

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::CopyFilePath);

				AddOperationMenu(filesMenu, idCmd, uidFirstCmd, pos, FileOps::Touch);
			}

			if (!IsInDisabledActionsList(FileOps::SortDesktop, disabledOpsList))
			{
				AddSortDesktopMenu(mainMenu, idCmd, pos, uidFirstCmd);
			}

			// List of Files - Menu Category
			HMENU informationMenu = CreateMenu();
			AddMenuSubItem(mainMenu, informationMenu, L"List of Files", idCmd, pos++, MenuPics::ICON_LIST_FULL); 

			// Adds List Of Files sub menus
			{
				UINT pos = 0;

				AddOperationMenu(informationMenu, idCmd, uidFirstCmd, pos, FileOps::FilesListDetailed);
				AddOperationMenu(informationMenu, idCmd, uidFirstCmd, pos, FileOps::FilesListDetailedFullPath);

				InsertMenu(informationMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(informationMenu, idCmd, uidFirstCmd, pos, FileOps::FilesListSimple);
				AddOperationMenu(informationMenu, idCmd, uidFirstCmd, pos, FileOps::FilesListSimpleFullPath);
			}

			// Security - Menu Category
			HMENU securityMenu = CreateMenu();
			AddMenuSubItem(mainMenu, securityMenu, L"Security", idCmd, pos++, MenuPics::ICON_SECURITY); 

			// Adds Security menus
			{
				UINT pos = 0;

				AddOperationMenu(securityMenu, idCmd, uidFirstCmd, pos, FileOps::EncryptFiles);
				AddOperationMenu(securityMenu, idCmd, uidFirstCmd, pos, FileOps::DecryptFiles, IsInDisabledActionsList(FileOps::DecryptFiles, disabledOpsList));
			}

			// Split - Menu Category
			HMENU splitMenu = CreateMenu();
			AddMenuSubItem(mainMenu, splitMenu, L"Split and Join", idCmd, pos++, MenuPics::ICON_SPLIT_JOIN); 

			// Adds Split menus
			{
				UINT pos = 0;

				AddOperationMenu(splitMenu, idCmd, uidFirstCmd, pos, FileOps::SplitFiles);
				AddOperationMenu(splitMenu, idCmd, uidFirstCmd, pos, FileOps::JoinFiles);
			}

			// Rename - Menu Category
			HMENU renameMenu = CreateMenu();
			AddMenuSubItem(mainMenu, renameMenu, L"Rename", idCmd, pos++, MenuPics::ICON_RENAME); 

			// Adds Rename menus
			{
				UINT pos = 0;

				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameFindReplace, false, true);
				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameAutoNumbering, false, true);
				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameAlphabetize, false, true);
				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameAppend, false, true);

				InsertMenu(renameMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameAutoNumberingWithAppend, false, true);
				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameAlphabetizeWithAppend, false, true);

				InsertMenu(renameMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameMakeSameName, IsInDisabledActionsList(FileOps::RenameMakeSameName, disabledOpsList), true);

				InsertMenu(renameMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(renameMenu, idCmd, uidFirstCmd, pos, FileOps::RenameTruncate, false, true);
			}

			// Image Resize - Menu Category
			HMENU imageMenu = CreateMenu();
			AddMenuSubItem(mainMenu, imageMenu, L"Image Manipulation", idCmd, pos++, MenuPics::ICON_IMAGE_TOPIC); 

			// Adds Image sub menus
			{
				UINT pos = 0;

				bool disableImageOps = IsInDisabledActionsList(FileOps::ShrinkImageFiles, disabledOpsList);

				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles, disableImageOps, true);

				InsertMenu(imageMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles25, disableImageOps, true);
				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles50, disableImageOps, true);
				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles75, disableImageOps, true);

				InsertMenu(imageMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles25Jpg, disableImageOps, true);
				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles50Jpg, disableImageOps, true);
				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles75Jpg, disableImageOps, true);

				InsertMenu(imageMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::ShrinkImageFiles100Jpg, disableImageOps, true);

				InsertMenu(imageMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(imageMenu, idCmd, uidFirstCmd, pos, FileOps::AddLogoToImage, disableImageOps, true);
			}

			// Image Resize - Menu Category
			HMENU imageAlbumMenu = CreateMenu();
			AddMenuSubItem(mainMenu, imageAlbumMenu, L"Image Album", idCmd, pos++, MenuPics::ICON_PICTURES); 

			{
				UINT pos = 0;

				bool disablePdfOps = IsInDisabledActionsList(FileOps::PdfImageAlbum, disabledOpsList);

				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbum, disablePdfOps, true);

				InsertMenu(imageAlbumMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumPhotoWallet, disablePdfOps, true);
				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumPhoto3_5x5, disablePdfOps, true);
				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumPhoto4x6, disablePdfOps, true);
				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumPhoto5x7, disablePdfOps, true);
				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumPhoto8x10, disablePdfOps, true);
				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumPhoto9x12, disablePdfOps, true);
				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumTwice8x10, disablePdfOps, true);
				AddOperationMenu(imageAlbumMenu, idCmd, uidFirstCmd, pos, FileOps::PdfImageAlbumQuad4x6, disablePdfOps, true);
			}
		}
	}

	InsertMenu(mainMenu,  pos++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

	AddOperationMenu(mainMenu, idCmd, uidFirstCmd, pos, FileOps::Settings);

	// Help - Menu Category
	HMENU helpMenu = CreateMenu();
	AddMenuSubItem(mainMenu, helpMenu, L"Help", idCmd, pos++, MenuPics::ICON_HELP); 

	// Adds Image sub menus
	{
		UINT pos = 0;

		AddOperationMenu(helpMenu, idCmd, uidFirstCmd, pos, FileOps::Contents);
		AddOperationMenu(helpMenu, idCmd, uidFirstCmd, pos, FileOps::About);
	}

	menuItemInfo.hSubMenu = mainMenu;

	if (m_IsVistaOs)
	{
		menuItemInfo.hbmpItem = s_MenuItemsHolder.m_Bitmaps[MenuPics::ICON_FROG];
	}
	else
	{
		menuItemInfo.hbmpItem = HBMMENU_CALLBACK;
		menuItemInfo.dwItemData = (ULONG_PTR)s_MenuItemsHolder.m_Icons[MenuPics::ICON_FROG];
	}

	menuItemInfo.dwTypeData = L"FilerFrog";
	menuItemInfo.cch = (UINT)wcslen(menuItemInfo.dwTypeData);


	// Insert Separator At First
	InsertMenu(hmenu, uMenuIndex++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);

	// Inserts Main Menu
	InsertMenuItem(hmenu, uMenuIndex++ , TRUE, &menuItemInfo);

	// Insert Separator At End
	InsertMenu(hmenu, uMenuIndex++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);


	return MAKE_HRESULT (SEVERITY_SUCCESS, FACILITY_NULL, idCmd - uidFirstCmd);
}


HRESULT CFilerFrogShellExt::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
	USES_CONVERSION;

	// Check idCmd, it must be 0 since we have only one menu item.
	if (idCmd != 0)
	{
		return E_INVALIDARG;
	}

	// If Explorer is asking for a help string, copy our string into the
	// supplied buffer.
	if (uFlags & GCS_HELPTEXT)
	{
		LPCTSTR szText = _T("FilerFrog");

		if (uFlags & GCS_UNICODE)
		{
			// We need to cast pszName to a Unicode string, and then use the
			// Unicode string copy API.
			lstrcpynW ( (LPWSTR) pszName, T2CW(szText), cchMax );
		}
		else
		{
			// Use the ANSI string copy API to return the help string.
			lstrcpynA ( pszName, T2CA(szText), cchMax );
		}

		return S_OK;
	}

	return E_INVALIDARG;
}

STDMETHODIMP CFilerFrogShellExt::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LRESULT res;
	return HandleMenuMsg2(uMsg, wParam, lParam, &res);
}

STDMETHODIMP CFilerFrogShellExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
{
	LRESULT res;

	if (pResult == NULL)
	{
		pResult = &res;
	}

	*pResult = FALSE;

	if (m_IsVistaOs)
	{
		return NOERROR;
	}

	switch (uMsg)
	{
	case WM_MEASUREITEM:
		{
			MEASUREITEMSTRUCT* lpmis = (MEASUREITEMSTRUCT*)lParam;

			if (lpmis == NULL)
			{
				break;
			}		

			lpmis->itemWidth = 5;
			lpmis->itemHeight = 16 + 4;

			*pResult = TRUE;
		}
		break;

	case WM_DRAWITEM:
		{
			DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;

			if ((lpdis==NULL)||(lpdis->CtlType != ODT_MENU))
			{
				return S_OK;		//not for a menu
			}

			HICON hIcon = (HICON)lpdis->itemData;

			if (hIcon == NULL)
			{
				return S_OK;
			}

			int x = 2;
			int y = 2;

			DrawIconEx(lpdis->hDC,
				x,
				y,
				hIcon, 16, 16,
				0, NULL, DI_NORMAL);

			*pResult = TRUE;
		}
		break;

	default:
		return NOERROR;

	}

	return NOERROR;
}

void CFilerFrogShellExt::ReportProgress(int progress, bool closeProgressWindow)
{
	// Sets the Marquee Style
	if (closeProgressWindow)
	{
		m_FrogProgressDialog.ShowWindow(SW_HIDE);
	}
	else if (!m_FrogProgressDialog.IsWindowVisible())
	{

		m_FrogProgressDialog.ShowWindow(SW_SHOW);
	}

	m_FrogProgressDialog.SetProgress(progress);
}

void CFilerFrogShellExt::ExecuteCommand()
{
	switch (m_CurrentOperation)
	{	
	case FileOps::ExtractFilesFromFolder:
		{
			m_FilesRefactor.ExtractFilesFromMultipleFolders(m_LastResult, m_FilesList);				
		}
		break;
		
	case FileOps::MoveUp:
		{
			m_FilesRefactor.MoveFilesUp(m_LastResult, m_FilesList);				
		}
		break;

	case FileOps::JoinFiles:
		{
			m_FilesRefactor.JoinFiles(m_LastResult, m_FilesList);
		}
		break;
	case FileOps::DeleteZeroLengthFiles:
		{
			m_FilesRefactor.DeleteZeroFiles(m_LastResult, m_FilesList);
		}
		break;
	case FileOps::PdfImageAlbumPhotoWallet:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				PDFPage page;

				wstring imageFileName = *iter;
				PDFTemplates::T_PageSinglePhotoWallet(page, imageFileName);
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);
		}
		break;
	case FileOps::PdfImageAlbumPhoto3_5x5:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				PDFPage page;

				wstring imageFileName = *iter;
				PDFTemplates::T_PageSinglePhoto3_5x5(page, imageFileName);
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);
		}
		break;
	case FileOps::PdfImageAlbumPhoto4x6:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				PDFPage page;

				wstring imageFileName = *iter;
				PDFTemplates::T_PageSinglePhoto4x6(page, imageFileName);
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);

		}
		break;
	case FileOps::PdfImageAlbumPhoto5x7:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				PDFPage page;

				wstring imageFileName = *iter;
				PDFTemplates::T_PageSinglePhoto5x7(page, imageFileName);
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);

		}
		break;
	case FileOps::PdfImageAlbumPhoto8x10:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				PDFPage page;

				wstring imageFileName = *iter;
				PDFTemplates::T_PageSinglePhoto8x10(page, imageFileName);
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);
		}
		break;
	case FileOps::PdfImageAlbumPhoto9x12:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				PDFPage page;

				wstring imageFileName = *iter;
				PDFTemplates::T_PageSinglePhoto9x12(page, imageFileName);
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);
		}
		break;
	case FileOps::PdfImageAlbumTwice8x10:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			wstring files[2];			
			int i = 0;

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				files[i] = *iter;
				i++;

				if (i == 2)
				{
					PDFPage page;
					PDFTemplates::T_320x464PageTwice8x10(page, true, files[0], files[1]);					
					pdfFile.AddPage(page);
					i = 0;

					files[0] = L"";
					files[1] = L"";
				}
			}

			if (i != 0)
			{
				PDFPage page;
				PDFTemplates::T_320x464PageTwice8x10(page, true, files[0], files[1]);
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);

		}
		break;
	case FileOps::PdfImageAlbumQuad4x6:
		{
			wstring pdfPath = m_FolderPath + L"\\PhotoAlbum.pdf";
			PDFFile pdfFile(pdfPath.c_str());

			wstring files[4];			
			int i = 0;

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter !=  m_FilesList.end(); iter++)
			{
				files[i] = *iter;
				i++;

				if (i == 4)
				{
					PDFPage page;
					PDFTemplates::T_320x464PageQuad4x6(page, true, false, files[0], files[1], files[2], files[3]);					
					pdfFile.AddPage(page);

					i = 0;

					files[0] = L"";
					files[1] = L"";
					files[2] = L"";
					files[3] = L"";
				}
			}

			if (i != 0)
			{
				PDFPage page;
				PDFTemplates::T_320x464PageQuad4x6(page, true, false, files[0], files[1], files[2], files[3]);					
				pdfFile.AddPage(page);
			}

			m_FilesRefactor.GeneratePdf(m_LastResult, pdfFile);
		}		
	case FileOps::FilesListDetailed:
		{
			m_FilesRefactor.MakeListOfFiles(m_LastResult, m_FilesList, m_ListFilePath, true, false, m_IncludeSubfolders, m_Indent, m_IsHtml);
		}
		break;
	case FileOps::FilesListDetailedFullPath:
		{
			m_FilesRefactor.MakeListOfFiles(m_LastResult, m_FilesList, m_ListFilePath, true, true, m_IncludeSubfolders, m_Indent, m_IsHtml);
		}
		break;
	case FileOps::FilesListSimple:
		{
			m_FilesRefactor.MakeListOfFiles(m_LastResult, m_FilesList, m_ListFilePath, false, false, m_IncludeSubfolders, m_Indent, m_IsHtml);
		}
		break;
	case FileOps::FilesListSimpleFullPath:
		{
			m_FilesRefactor.MakeListOfFiles(m_LastResult, m_FilesList, m_ListFilePath, false, true, m_IncludeSubfolders, m_Indent, m_IsHtml);
		}
		break;
	}
}

void CFilerFrogShellExt::ExecuteCommandWithProgressBar(HWND parent)
{
	m_FrogProgressDialog.SetIcon(s_MenuItemsHolder.m_Icons[s_MenuItemsHolder.m_CmdIcon[m_CurrentOperation]]);
	// m_FrogProgressDialog.SetWindowText("");
	m_FrogProgressDialog.m_MarqueeProgressBar = true;
	m_FrogProgressDialog.DoModal(parent);
}

void CFilerFrogShellExt::ShowImageResizeFastDialog(HICON currentCommandIcon, HWND hwnd, double shrinkBy, bool saveAsJpeg)
{
	CFrogImageResizeFastDialog frogImageResizeFastDialog(currentCommandIcon);
	frogImageResizeFastDialog.m_FilesList = m_FilesList;

	frogImageResizeFastDialog.m_SaveJPG = saveAsJpeg;
	frogImageResizeFastDialog.m_ShrinkBy = shrinkBy;

	if (frogImageResizeFastDialog.DoModal(hwnd) == IDOK)
	{
		m_LastResult = frogImageResizeFastDialog.m_LastResult;				
	}
	else
	{
		m_NeedsRefresh = false;
	}		
}

HRESULT CFilerFrogShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo)
{
	HRESULT retVal = S_OK;

	m_LastResult.Kind = FRRESPONSE_ENUM::SUCCESS;
	m_LastResult.NewFiles.clear();
	m_LastResult.NumOfFailed = 0;
	m_LastResult.NumOfSucceeded = 0;
	m_LastResult.Text = L"";

	m_NeedsRefresh = true;

	// If lpVerb really points to a string, ignore this function call and bail out.
	if (HIWORD(pCmdInfo->lpVerb) != 0)
	{
		return E_INVALIDARG;
	}

	// .lnk files fix
	if (pCmdInfo->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && (pCmdInfo->fMask & CMIC_MASK_UNICODE) == CMIC_MASK_UNICODE)
	{
		CMINVOKECOMMANDINFOEX* pCmdInfoEx = (CMINVOKECOMMANDINFOEX*)pCmdInfo;
		m_FolderPath = pCmdInfoEx->lpDirectoryW;
	}
	else
	{
		// But if we do convert first item to directory and hope for the best...
		m_FolderPath = FilerFrogUtils::GetFileDirectoyPath(m_FilesList.front());
	}

	FileOps oprerationCode = (FileOps) m_MenuCommandMap[(LOWORD(pCmdInfo->lpVerb))];

	m_CurrentOperation = oprerationCode;

	m_FilesRefactor.SetParentWindow(NULL);

	HICON currentCommandIcon = NULL;

	if (oprerationCode >= 0 &&  oprerationCode < MAX_MENU_ICONS)
	{
		currentCommandIcon = s_MenuItemsHolder.m_Icons[s_MenuItemsHolder.m_CmdIcon[oprerationCode]];
	}

	// Get the command index - the only valid one is 0.
	switch (oprerationCode)
	{
	case FileOps::ExtractFilesToFolder:
		{
			CFrogExtractFolderDialog frogExtractFolderDialog(currentCommandIcon);
			frogExtractFolderDialog.m_FilesList = m_FilesList;
			frogExtractFolderDialog.m_FolderPath = m_FolderPath;

			if (frogExtractFolderDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogExtractFolderDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::ExtractFilesFromFolder:
	case FileOps::MoveUp:	
		{
			ExecuteCommandWithProgressBar(pCmdInfo->hwnd);			
		}
		break;

	case FileOps::ShrinkImageFiles25:
		{
			ShowImageResizeFastDialog(currentCommandIcon, pCmdInfo->hwnd, 0.25, false);
		}
		break;
	case FileOps::ShrinkImageFiles50:
		{
			ShowImageResizeFastDialog(currentCommandIcon, pCmdInfo->hwnd, 0.5, false);
		}
		break;
	case FileOps::ShrinkImageFiles75:
		{
			ShowImageResizeFastDialog(currentCommandIcon, pCmdInfo->hwnd, 0.75, false);
		}
		break;
	case FileOps::ShrinkImageFiles25Jpg:
		{
			ShowImageResizeFastDialog(currentCommandIcon, pCmdInfo->hwnd, 0.25, true);
		}
		break;
	case FileOps::ShrinkImageFiles50Jpg:
		{
			ShowImageResizeFastDialog(currentCommandIcon, pCmdInfo->hwnd, 0.5, true);
		}
		break;
	case FileOps::ShrinkImageFiles75Jpg:
		{
			ShowImageResizeFastDialog(currentCommandIcon, pCmdInfo->hwnd, 1.0, true);
		}
		break;
	case FileOps::ShrinkImageFiles100Jpg:
		{
			ShowImageResizeFastDialog(currentCommandIcon, pCmdInfo->hwnd, 1.0, true);
		}
		break;

	case FileOps::AddLogoToImage:
		{
			CFrogImageLogoDialog frogImageLogoDialog(currentCommandIcon);
			frogImageLogoDialog.m_FilesList = m_FilesList;

			if (frogImageLogoDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogImageLogoDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::JoinFiles:
	case FileOps::DeleteZeroLengthFiles:
	case FileOps::PdfImageAlbumPhotoWallet:
	case FileOps::PdfImageAlbumPhoto3_5x5:
	case FileOps::PdfImageAlbumPhoto4x6:
	case FileOps::PdfImageAlbumPhoto5x7:
	case FileOps::PdfImageAlbumPhoto8x10:
	case FileOps::PdfImageAlbumPhoto9x12:
	case FileOps::PdfImageAlbumTwice8x10:
	case FileOps::PdfImageAlbumQuad4x6:
		{
			ExecuteCommandWithProgressBar(pCmdInfo->hwnd);
		}
		break;

	case FileOps::ShrinkImageFiles:
		{
			CFrogImageResizeDialog frogImageResizeDialog(currentCommandIcon);
			frogImageResizeDialog.m_FilesList = m_FilesList;

			if (frogImageResizeDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogImageResizeDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::PdfImageAlbum:
		{
			CFrogPdfAlbumDialog pdfAlbumDialog(m_FilesList, currentCommandIcon);
			pdfAlbumDialog.m_FilesList = m_FilesList;
			pdfAlbumDialog.m_FolderPath = m_FolderPath;

			if (pdfAlbumDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = pdfAlbumDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::SplitFiles:
		{
			CFrogSplitDialog frogSplitDialog(currentCommandIcon);
			frogSplitDialog.m_FilesList = m_FilesList;

			if (frogSplitDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogSplitDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::FilesListDetailed:
	case FileOps::FilesListDetailedFullPath:
	case FileOps::FilesListSimple:
	case FileOps::FilesListSimpleFullPath:
		{
			CFrogFileListDialog frogFileListDialog(currentCommandIcon);

			if (frogFileListDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				wstring fileListName = frogFileListDialog.m_FileList;
				m_ListFilePath = m_FolderPath + wstring(L"\\") + fileListName;

				m_IsHtml = frogFileListDialog.m_Html;
				m_IncludeSubfolders = frogFileListDialog.m_IncludeSubfolders;
				m_Indent = frogFileListDialog.m_Indent;				

				ExecuteCommandWithProgressBar(pCmdInfo->hwnd);
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;
	case FileOps::CopyFiles:
		{
			wstring destFolder = L"";

			BROWSEINFO bi;
			ZeroMemory(&bi, sizeof(BROWSEINFO));

			bi.hwndOwner = pCmdInfo->hwnd;
			bi.ulFlags = BIF_RETURNONLYFSDIRS;
			bi.lpszTitle = L"Please select a destination folder to copy selected files";

			LPITEMIDLIST pidl = SHBrowseForFolder(&bi);

			TCHAR szPathName[MAX_PATH]; 

			if (pidl != NULL)
			{
				if (SHGetPathFromIDList(pidl, szPathName) != FALSE)
				{
					destFolder = szPathName;

					m_RecentActionsManager.AddCopyPath(destFolder);
					m_RecentActionsManager.SaveAll();

					m_FilesRefactor.CopyFiles(m_LastResult, m_FilesList, destFolder);
				}
			}
		}
		break;

	case FileOps::CopyFilesRecent00:
	case FileOps::CopyFilesRecent01:
	case FileOps::CopyFilesRecent02:
	case FileOps::CopyFilesRecent03:
	case FileOps::CopyFilesRecent04:
		{
			int idx = int(oprerationCode - FileOps::CopyFilesRecent00);
			wstring destFolder = m_RecentActionsManager.m_LastCopyPaths[idx];
			m_FilesRefactor.CopyFiles(m_LastResult, m_FilesList, destFolder);
		}
		break;

	case FileOps::MoveFiles:
		{
			wstring destFolder = L"";

			BROWSEINFO bi;
			ZeroMemory(&bi, sizeof(BROWSEINFO));

			bi.hwndOwner = pCmdInfo->hwnd;
			bi.ulFlags = BIF_RETURNONLYFSDIRS;
			bi.lpszTitle = L"Please select a destination folder to move selected files";

			LPITEMIDLIST pidl = SHBrowseForFolder(&bi);

			TCHAR szPathName[MAX_PATH]; 

			if (pidl != NULL)
			{
				if (SHGetPathFromIDList(pidl, szPathName) != FALSE)
				{
					destFolder = szPathName;

					m_RecentActionsManager.AddMovePath(destFolder);
					m_RecentActionsManager.SaveAll();

					m_FilesRefactor.MoveFiles(m_LastResult, m_FilesList, destFolder);
				}
			}
		}
		break;

	case FileOps::MoveFilesRecent00:
	case FileOps::MoveFilesRecent01:
	case FileOps::MoveFilesRecent02:
	case FileOps::MoveFilesRecent03:
	case FileOps::MoveFilesRecent04:
		{
			int idx = int(oprerationCode - FileOps::MoveFilesRecent00);
			wstring destFolder = m_RecentActionsManager.m_LastMovePaths[idx];
			m_FilesRefactor.MoveFiles(m_LastResult, m_FilesList, destFolder);
		}
		break;

	case FileOps::EncryptFiles:
		{
			CFrogEncryptDialog frogEncryptDialog(currentCommandIcon);
			frogEncryptDialog.m_FilesList = m_FilesList;

			if (frogEncryptDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogEncryptDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;
	case FileOps::DecryptFiles:
		{
			CFrogDecryptDialog frogDecryptDialog(currentCommandIcon);
			frogDecryptDialog.m_FilesList = m_FilesList;

			if (frogDecryptDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogDecryptDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::RenameAlphabetize:
		{
			CFrogRenameAutoAlphaDialog frogRenameAutoAlphaDialog(currentCommandIcon);
			frogRenameAutoAlphaDialog.m_FilesList = m_FilesList;

			if (frogRenameAutoAlphaDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameAutoAlphaDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::RenameAlphabetizeWithAppend:
		{
			CFrogRenameAutoAlphaAppendDialog frogRenameAutoAlphaAppendDialog(currentCommandIcon);
			frogRenameAutoAlphaAppendDialog.m_FilesList = m_FilesList;

			if (frogRenameAutoAlphaAppendDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameAutoAlphaAppendDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::RenameAutoNumbering:
		{
			CFrogRenameAutoNumDialog frogRenameAutoNumDialog(currentCommandIcon);
			frogRenameAutoNumDialog.m_FilesList = m_FilesList;

			if (frogRenameAutoNumDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameAutoNumDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::RenameAutoNumberingWithAppend:
		{
			CFrogRenameAutoNumAppendDialog frogRenameAutoNumAppendDialog(currentCommandIcon);
			frogRenameAutoNumAppendDialog.m_FilesList = m_FilesList;

			if (frogRenameAutoNumAppendDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameAutoNumAppendDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::RenameAppend:
		{
			CFrogRenameAppendDialog frogRenameAppendDialog(currentCommandIcon);
			frogRenameAppendDialog.m_FilesList = m_FilesList;

			if (frogRenameAppendDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameAppendDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;
	case FileOps::RenameFindReplace:
		{
			CFrogRenameFindReplaceDialog frogRenameFindReplaceDialog(currentCommandIcon);
			frogRenameFindReplaceDialog.m_FilesList = m_FilesList;

			if (frogRenameFindReplaceDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameFindReplaceDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::RenameMakeSameName:
		{
			CFrogRenameSameNameDialog frogRenameSameNameDialog(currentCommandIcon);
			frogRenameSameNameDialog.m_FilesList = m_FilesList;

			if (frogRenameSameNameDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameSameNameDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}
		break;

	case FileOps::RenameTruncate:
		{
			CFrogRenameTruncateDialog frogRenameTruncateDialog(currentCommandIcon);
			frogRenameTruncateDialog.m_FilesList = m_FilesList;

			if (frogRenameTruncateDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{
				m_LastResult = frogRenameTruncateDialog.m_LastResult;
			}
			else
			{
				m_NeedsRefresh = false;
			}
		}

		break;

	case FileOps::InvertSelection:
		{
			m_NeedsRefresh = false;
			m_ExplorerController.InvertFilesSelection();
		}
		break;

	case FileOps::CopyFilePath:
		{
			m_NeedsRefresh = false;

			wstring filesPaths = L"";

			int i = 0;
			size_t count = m_FilesList.size();

			for (list<wstring>::iterator iter = m_FilesList.begin(); iter != m_FilesList.end(); iter++)
			{
				if (i == count - 1)
				{
					filesPaths = filesPaths + *iter;
				}
				else
				{
					filesPaths = filesPaths + *iter + L"\r\n";
				}

				i++;
			}

			FilerFrogUtils::CopyStringToClipboard(filesPaths);
		}
		break;

	case FileOps::Touch:
		{
			m_FilesRefactor.TouchFiles(m_LastResult, m_FilesList);
		}
		break;
	case FileOps::SortDesktop:
		{
			m_NeedsRefresh = false;

			CFrogSortDesktopDialog frogSortDesktopDialog(currentCommandIcon);

			if (frogSortDesktopDialog.DoModal(pCmdInfo->hwnd) == IDOK)
			{				
				m_ExplorerController.SortItemsByPathList(frogSortDesktopDialog.s_DesktopSortConfig);
			}
		}
		break;

	case FileOps::SortDesktopRedo:
		{
			m_NeedsRefresh = false;

			if (FrogMessageBox(pCmdInfo->hwnd, L"Redo Last Desktop Sort?", L"FilerFrog - Redo Last Desktop Sort", MB_ICONQUESTION | MB_YESNO) == IDYES)
			{				
				m_ExplorerController.SortItemsByPathListWithLastConfig();
			}
		}
		break;

	case FileOps::SortDesktopBlueSky:
		{
			m_NeedsRefresh = false;

			DesktopSortConfigBlueSky desktopSortConfigBlueSky;
			m_ExplorerController.SortItemsByPathList(desktopSortConfigBlueSky);
		}
		break;

	case FileOps::SortDesktopEggPlant:
		{
			m_NeedsRefresh = false;

			DesktopSortConfigEggPlant desktopSortConfigEggPlant;
			m_ExplorerController.SortItemsByPathList(desktopSortConfigEggPlant);
		}
		break;

	case FileOps::SortDesktopSunset:
		{
			m_NeedsRefresh = false;

			DesktopSortConfigSunset desktopSortConfigSunset;
			m_ExplorerController.SortItemsByPathList(desktopSortConfigSunset);
		}
		break;

	case FileOps::SortDesktopDark:
		{
			m_NeedsRefresh = false;

			DesktopSortConfigDesktopDark desktopSortConfigDesktopDark;
			m_ExplorerController.SortItemsByPathList(desktopSortConfigDesktopDark);
		}
		break;

	case FileOps::Settings:
		{
			m_NeedsRefresh = false;
			CFrogSettingsDialog* frogSettingsDialog = new CFrogSettingsDialog(currentCommandIcon);
			frogSettingsDialog->Create(pCmdInfo->hwnd);
		}
		break;

	case FileOps::About:
		{
			m_NeedsRefresh = false;
			CFrogAboutDialog* frogAboutDialog = new CFrogAboutDialog(currentCommandIcon);
			frogAboutDialog->Create(pCmdInfo->hwnd);
		}
		break;

	case FileOps::Contents:
		{
			m_NeedsRefresh = false;

			// Opens the Help file
			TCHAR szPath[MAX_PATH];

			if (GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szPath, MAX_PATH))
			{
				wstring helpFilePath = FilerFrogUtils::GetFileDirectoyPath(szPath) + L"\\FilerFrogHelp.chm";

				HWND desktopHwnd = GetDesktopWindow();

				RECT rect;
				GetWindowRect(desktopHwnd, &rect);

				int w = 800;
				int h = 600;

				int x = ((rect.right - rect.left) / 2) - (w / 2);
				int y = ((rect.bottom - rect.top) / 2) - (h / 2);

				HWND helpHwnd =  HtmlHelp(pCmdInfo->hwnd, helpFilePath.c_str(), HH_DISPLAY_TOPIC, 0);

				MoveWindow(helpHwnd, x, y, w, h, TRUE);
			}
		}
		break;

	case FileOps::ManageFavorites:
		{
			m_NeedsRefresh = false;
			CFrogFavoriteDialog::OpenManagementWindow(pCmdInfo->hwnd);
		}
		break;

	default:
		retVal = E_INVALIDARG;
		break;
	}

	if (oprerationCode < FileOps::About)
	{
		if (m_LastResult.Kind == FRRESPONSE_ENUM::SUCCESS && m_LastResult.NewFiles.size() > 0)
		{		
			m_ExplorerController.SelectItemsByPathList(m_LastResult.NewFiles);
		}
		else if (m_NeedsRefresh)
		{
			m_ExplorerController.RefreshFolderView();
			HandleErrorMesseages(m_LastResult, pCmdInfo->hwnd);
		}
	}	

	return retVal;
}

void CFilerFrogShellExt::HandleErrorMesseages(FRRESPONSE result, HWND parent)
{
	// Error
	wchar_t errorTitle[512];
	wchar_t errorInfo[1024];

	if (result.Kind != FRRESPONSE_ENUM::SUCCESS && result.Kind != FRRESPONSE_ENUM::FAIL_USER_DECIDED)
	{
		switch (result.Type)
		{
		case ACTION_TYPE::EXTRACT_FROM_FOLDER:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Extract From Folder Operation Error");
			}
			break;
		case ACTION_TYPE::EXTRACT_TO_FOLDER:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Extract To Folder Operation Error");
			}
			break;
		case ACTION_TYPE::COPY:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Copy Operation Error");
			}
			break;
		case ACTION_TYPE::MOVE:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Move Operation Error");
			}
			break;
		case ACTION_TYPE::MAKE_LIST:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - List of Files Operation Error");
			}
			break;
		case ACTION_TYPE::RESIZE_IMAGE:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Resize Image Operation Error");
			}
			break;
		case ACTION_TYPE::DELETE_ZERO:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Delete Empty Files or Folders Operation Error");
			}
			break;
		case ACTION_TYPE::SPLIT:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Split Operation Error");
			}
			break;
		case ACTION_TYPE::JOIN:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Join Operation Error");
			}
			break;
		case ACTION_TYPE::PDF_ALBUM:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Image Album Operation Error");
			}
			break;
		case ACTION_TYPE::ENCRYPT:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Encrypt Operation Error");
			}
			break;
		case ACTION_TYPE::DECRYPT:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Decrypt Operation Error");
			}
			break;
		case ACTION_TYPE::RENAME:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Rename Operation Error");
			}
			break;

		case ACTION_TYPE::TOUCH_FILES:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Touch Files Operation Error");
			}
			break;

		case ACTION_TYPE::UNHIDE:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Operation Error");
			}
			break;

		default:
			{
				wcscpy_s(errorTitle, 512, L"FilerFrog - Operation Error");
			}
			break;
		}		

		wcscpy_s(errorInfo, 512, result.Text.c_str());

		HICON currentCommandIcon = NULL;		

		if (m_CurrentOperation >= 0 &&  m_CurrentOperation < MAX_MENU_ICONS)
		{
			currentCommandIcon = s_MenuItemsHolder.m_Icons[s_MenuItemsHolder.m_CmdIcon[m_CurrentOperation]];
		}

		CFrogErrorDialog frogErrorDialog(currentCommandIcon);
		frogErrorDialog.m_ErrorTitle = errorTitle;
		frogErrorDialog.m_ErrorInfo = errorInfo;

		frogErrorDialog.DoModal(parent);
	}
}

void CFilerFrogShellExt::ExternalDecryptFileDialog(const wstring& filePath)
{
	m_FilesList.clear();
	m_FilesList.push_back(filePath);

	FileOps oprerationCode = (FileOps::DecryptFiles);	
	m_CurrentOperation = oprerationCode;

	HICON currentCommandIcon = NULL;

	if (oprerationCode >= 0 &&  oprerationCode < MAX_MENU_ICONS)
	{
		currentCommandIcon = s_MenuItemsHolder.m_Icons[s_MenuItemsHolder.m_CmdIcon[oprerationCode]];
	}

	CFrogDecryptDialog frogDecryptDialog(currentCommandIcon);
	frogDecryptDialog.m_FilesList = m_FilesList;

	if (frogDecryptDialog.DoModal() == IDOK)
	{		
		wstring filePath = m_FilesList.front();
		wstring dir = FilerFrogUtils::GetFileDirectoyPath(filePath);
		SHChangeNotify(SHCNE_UPDATEDIR,SHCNF_PATH, dir.c_str(), NULL);			

		size_t extLen = wcslen(ENCRYPTION_EXTENSION);
		size_t len = filePath.length();

		size_t pos = len - extLen - 1;

		if (pos < 0)
		{
			pos = 0;
		}

		wstring filePathToOpen = filePath.substr(0, pos);

		if (PathFileExists(filePathToOpen.c_str()) == TRUE)
		{
			ShellExecute(NULL, NULL, filePathToOpen.c_str(), NULL, NULL, SW_SHOWNORMAL);
		}
	}
}

void CFilerFrogShellExt::ExternalJoinFileDialog(const wstring& filePath)
{
	if (filePath == L"")
	{
		return;
	}

	m_FilesList.clear();
	m_FilesList.push_back(filePath);

	// Find all other splited files...
	list<wstring> allFilesInDir;
	FilerFrogUtils::MakeListInDir(FilerFrogUtils::GetFileDirectoyPath(filePath), allFilesInDir);

	wstring defaultExt = SPLIT_EXTENSION;

	wstring fileWithoutExt = FilerFrogUtils::GetFileNameWithoutExtension(filePath);
	wstring fileExt = FilerFrogUtils::GetFileNameExtension(filePath);

	for (list<wstring>::iterator iter = allFilesInDir.begin(); iter != allFilesInDir.end(); iter++)
	{
		if (*iter != filePath)
		{
			wstring fileWithoutExt2 = FilerFrogUtils::GetFileNameWithoutExtension(*iter);

			if (fileWithoutExt == fileWithoutExt2)
			{
				wstring fileExt2 = FilerFrogUtils::GetFileNameExtension(*iter);

				if (defaultExt.length() < fileExt2.length() && fileExt2.substr(0, defaultExt.length()) ==  defaultExt)
				{
					// Check that ext must be a number
					wstring numStr = fileExt2.substr(defaultExt.length(), fileExt2.length() - defaultExt.length());

					bool isNumeric = true;

					for (int i=0; i< (int)numStr.length(); i++)
					{
						if (numStr.at(i) < L'0' || numStr.at(i) > L'9')
						{
							isNumeric = false;
							break;
						}
					}					

					if (isNumeric)
					{	
						m_FilesList.push_back(*iter);
					}
				}
			}
		}
	}

	FileOps oprerationCode = (FileOps::JoinFiles);	
	m_CurrentOperation = oprerationCode;

	ExecuteCommandWithProgressBar(NULL);
	//if (s_OpertationWasDone)
	{
		wstring filePath = m_FilesList.front();
		wstring dir = FilerFrogUtils::GetFileDirectoyPath(filePath);
		SHChangeNotify(SHCNE_UPDATEDIR,SHCNF_PATH, dir.c_str(), NULL);
	}
}
